-- cupcake.lua
-- Gives people cupcakes >.>
-- Version 1.7
-- By Tyrone

---------------------------------------

--[[
Changelog:
1.7
-Saves cupcakecount in SQL

1.6.3
-Fixed voidboi's defect

1.6.2
-Adjusted self cupcake chances.

1.6.1
-fixed grammatical/spelling errors
-diarrhoea is now worth 15

1.6
-added cupcake queue
-normal users now get kicked after 15 cupcakes down from 10
-normal users now get banned for 1 minute, down from 5
 -chance for self-cupcake and self-fairbread is now 1/15 down from 1/10

1.5
-Ops can now be cupcaked
-Ops need 1338 cupcakes before kick
-People can charge their cupcakes :D

1.4
-People who cupcake and leave are punished.

1.3
-Time left is now keyed by IP, not user name.

1.2
-Can now cupcake the whole hub if user is uncupcakeable.

1.1
-There are now uncupcakeable users

1.0
-Direct port of cupcake.java as seen in VoidWare.

]]



-- set up all command prefixes
cmdNames = {
    "cupcake",
	"charge"
}
cannotBeCupcaked = {
	Aethereal = true;
	VoidBoi = true;
}


COOLDOWN = 60 -- plugin cooldown, 0 for none
_,bot_name = VH:GetConfig("config", "hub_security")
table_name = "cupcakes"
bot_desc = "bot description here"
bot_email = "bot@nowhere.com"
use_bot = false

function Main()
	SendQuery("CREATE TABLE IF NOT EXISTS "..table_name.." (id MEDIUMINT(8) UNSIGNED NOT NULL AUTO_INCREMENT, name VARCHAR(32) NOT NULL, count SMALLINT(4), PRIMARY KEY (id));")

	--Now we should load everything from the table
	loadFromSQL()
end

function loadFromSQL()
	ret, rows = VH:SQLQuery("SELECT name, count FROM cupcakes;")
	for i = 0, rows, 1 do
		res, name, count = VH:SQLFetch(i)
		if (not res) then break end
		if (name == nil) then break end
		if (count == nil) then break end
		--SendMessageToHub(name.."="..count,bot_name)
		cupcakes[name] = count
	end
end

function doCommand(nick, data, cmd)
	if (cmd == "cupcake") then
		victim = rtrim(data)
		if (timeLeft[UserIP(nick)] == nil) then
			timeLeft[UserIP(nick)] = 0
		end
		
		if (punish[UserIP(nick)] == nil) then
			punish[UserIP(nick)] = false
		end
		
		if (victim == "") or (victim == nil) then
			if (cupcakes[nick] == nil) then
				cupcount = 0
			else
				cupcount = cupcakes[nick]
			end
			SendMessageToUser("You have "..cupcount.." cupcakes!", nick, bot_name)
		elseif (timeLeft[UserIP(nick)] > 0) then
			SendMessageToUser("You must wait at least 15 seconds between uses of .cupcake ("..timeLeft[UserIP(nick)].."s left)", nick, bot_name)
		elseif (victim == "reset") and (UserClass(nick) > 4) then
			for name,count in pairs(cupcakes) do
				cupcakes[name] = 0
				SendQuery("UPDATE "..table_name.." SET count="..cupcakes[name].." WHERE (name='"..name.."');")
			end
		elseif (victim == "hub") then
			if (UserClass(nick) > 4) or (cannotBeCupcaked[nick] ~= nil) then
				--cupcake the ENTIRE GOD DAMN HUB
				_,nicklist = VH:GetNickList()
				nicklist = string.sub(nicklist, 11)
				for names in string.gmatch(nicklist, "([^%$]+)%$%$") do
					if (UserIsOnline(names)) then --they aren't a bot
						addCake(names)
						if (UserClass(nick) < 4) then
							timeLeft[UserIP(nick)] = 15
						else
							timeLeft[UserIP(nick)] = 5
						end
					end
				end
				SendEmoteToHub("cupcakes THE WHOLE GOD DAMN HUB :O", nick)
			else
				SendEmoteToHub("cupcakes themselves.", nick)
				addCake(nick)
				if (UserClass(nick) < 4) then
					timeLeft[UserIP(nick)] = 15
				else
					timeLeft[UserIP(nick)] = 5
				end
			end
		elseif (UserIsOnline(victim) ~= true) then
			--cupcake queue
			queue[victim] = nick
			timeLeft[UserIP(nick)] = 15
			SendMessageToUser(victim.." is not online right now.  They will be cupcaked when they rejoin the hub. ;)", nick, bot_name)
		--elseif (cannotBeCupcaked[victim] ~= nil) then
			--SendEmoteToHub("fairybreads all over "..nick..", because they tried to cupcake an uncupcakeable user.", victim)
			--addCake(nick)
			--addCake(nick)
			--addCake(nick)
			--timeLeft[UserIP(nick)] = 15
		elseif (punish[UserIP(nick)] == true) then
			SendEmoteToHub("diarrhoea's all over "..nick..", because they left too soon after cupcaking someone last time.  PLAY FAIR YOU WHORE.", bot_name)
			punish[UserIP(nick)] = false
			addCake(nick)
			addCake(nick)
			addCake(nick)
			addCake(nick)
			addCake(nick)
			addCake(nick)
			addCake(nick)
			addCake(nick)
			addCake(nick)
			addCake(nick)
			addCake(nick)
			addCake(nick)
			addCake(nick)
			addCake(nick)
			addCake(nick)
		else
			if (chargin[nick] == nil) then
				chargin[nick] = 0
			end
			
			if (chargin[nick] > 0) then
				if (chargin[nick] < 60) then
					chargin[nick] = 1
				else
					chargin[nick] = math.floor(chargin[nick] / 60)
				end
			else
				chargin[nick] = 1
			end
			
			if (chargin[nick] > 1) then
				SendMessageToHub("IMMA FIRIN MAH CUPCAKE!!!", nick)
			end
			
			while (chargin[nick] > 0) do
				performCake(victim, nick)
				chargin[nick] = chargin[nick] - 1
			end
			chargin[nick] = 0
		end
	elseif (cmd == "charge") then
		if (chargin[nick] == nil) then
			chargin[nick] = 0
		end
		
		if (chargin[nick] == 0) then
			SendMessageToHub("IMMA CHARGIN MAH CUPCAEK!!1one", nick)
			chargin[nick] = 1
		else
			chargeTime = chargin[nick]
			if (chargeTime > 300) then chargeTime = 300 end
			SendMessageToUser("You're already charging your cupcake.  It has been charging for "..chargeTime.." seconds.", nick, bot_name)
		end
	else --wtf?
	end
end

-- trim trailing spaces
function rtrim(s)
	if (s == nil) then return nil end
	local n = #s
	while n > 0 and s:find("^%s", n) do n = n - 1 end
	return s:sub(1, n)
end
-- end void's edit

function doHelp(nick)
    SendMessageToUser("Usage: ", nick, bot_name)
    DisplayHelpMessage("help", "Shows this message.", nick)
    -- put coad in here for help commands:
	DisplayHelpMessage("", "Shows your cupcake count.", nick)
    DisplayHelpMessage("username", "Cupcakes username.", nick)
	if (UserClass(nick) == 10) or (cannotBeCupcaked[nick] ~= nil) then
		DisplayHelpMessage("hub", "Cupcakes the entire god damn hub.", nick)
	end
end

-- insert other functions here

function addCake(nick)
	if (cupcakes[nick] == nil) then
		cupcakes[nick] = 1
		SendQuery("INSERT INTO cupcakes (id, name, count) VALUES (NULL,'"..nick.."',1);")
	else
		cupcakes[nick] = cupcakes[nick] + 1
	end
	
	if (UserClass(nick) > 4) or (cannotBeCupcaked[nick] ~= nil) then
		if (cupcakes[nick] > 1337) then
			cupcakes[nick] = 0
			SendEmoteToHub("dies a death by a massive cupcake overdose!!! (30 minute ban applied, lolz)", nick)
			VH:KickUser(bot_name, nick, "Cupcaked to death_ban_30m")
			_,nicklist = VH:GetNickList()
			nicklist = string.sub(nicklist, 11)
			for names in string.gmatch(nicklist, "([^%$]+)%$%$") do
				if (UserIP(nick) == UserIP(names)) then --lol fixing a sploit :O
					VH:CloseConnection(names)
				end
			end
			punish[UserIP(nick)] = false
			forgive[UserIP(nick)] = true
		end
	else
		if (cupcakes[nick] >= 15) then
			cupcakes[nick] = 0
			SendEmoteToHub("dies a death by cupcake. (1 minute ban applied, lolz)", nick)
			VH:KickUser(bot_name, nick, "Cupcaked to death_ban_1m")
			_,nicklist = VH:GetNickList()
			nicklist = string.sub(nicklist, 11)
			for names in string.gmatch(nicklist, "([^%$]+)%$%$") do
				if (UserIP(nick) == UserIP(names)) then --lol fixing a sploit :O
					VH:CloseConnection(names)
				end
			end
			punish[UserIP(nick)] = false
			forgive[UserIP(nick)] = true
		end
	end
	SendQuery("UPDATE "..table_name.." SET count="..cupcakes[nick].." WHERE (name='"..nick.."');")
end

function performCake(victim, caker)
	random = math.random(0,20)
	if (random == 0) then
		random = math.random(0,20)
		if (random == 0) then
			SendEmoteToHub("accidentally fairybreads all over themselves.", caker)
			addCake(caker)
			addCake(caker)
			addCake(caker)
		else
			SendEmoteToHub("accidentally cupcakes themselves.", caker)
			addCake(caker)
		end
	elseif (random == 1) then
		SendEmoteToHub("fairybreads all over "..victim..".", caker)
		addCake(victim)
		addCake(victim)
		addCake(victim)
	else
		SendEmoteToHub("cupcakes "..victim..".", caker)
		addCake(victim)
	end
	if (UserClass(caker) < 4) then
		timeLeft[UserIP(caker)] = 15
	else
		timeLeft[UserIP(caker)] = 5
	end
end

cupcakes = {}
---------------------------------------
-- you can ignore below here
timeLeft = {}
punish = {}
chargin = {}
forgive = {}
queue = {}

function UnLoad()
	if (use_bot) then
    	VH:DelRobot(bot_name)
	end
end

function VH_OnParsedMsgChat(nick, data)
    for i=1, table.maxn(cmdNames), 1 do
		if (string.find(data, "^%."..cmdNames[i])) then
		    _,_,cmd = string.find(data, "^%."..cmdNames[i].."%s(.+)")
		    if (cmd == "help") then
		        doHelp(nick)
		    else
        		doCommand(nick, cmd, cmdNames[i])
        	end
    		return 0
    	end
	end
	return 1
end

function ready(nick)
    if (timeLeft[nick] == 0) then
		timeLeft[nick] = COOLDOWN
	elseif (timeLeft[nick] == nil) then
		timeLeft[nick] = COOLDOWN
	else
		SendMessageToUser("This command can only be used every "..COOLDOWN.." seconds.  You have "..timeLeft[nick].." seconds to wait.", nick, bot_name)
		return true
	end
	return false
end

function SendQuery(query)
	local res, err = VH:SQLQuery(query)
	if (not res) then
		SendMessageToHub("An error has occurred!  :( \n"..err.."\nQuery="..query, bot_name)
	end
end

function SendMessageToHub(data, from)
	return VH:SendDataToAll("<"..from.."> "..data.."|",0,10)
end

function SendMessageToUser(data, nick, from)
	return VH:SendDataToUser("<"..from.."> "..data.."|", nick)
end

function SendPrivateMessageToUser(user, data, from)
    return VH:SendDataToUser("$To: "..user.." From: "..from.." $<"..from.."> "..data.."|", user);
end

function DisplayHelpMessage(cmd, msg, nick)
    SendMessageToUser("        ."..cmdNames[1].." "..cmd, nick, bot_name)
    SendMessageToUser("        "..msg, nick, bot_name)
end

function UserIsOnline(nick)
	result, sIP = VH:GetUserIP(nick)
	if (string.len(sIP) < 7) then
		return false
	else
		return true
	end
end

function UserIP(nick)
	result, sIP = VH:GetUserIP(nick)
	if (string.len(sIP) < 7) then
		return 0
	else
		return sIP
	end
end

function UserClass(nick)
	res, class = VH:GetUserClass(nick)
	if res and class then return class else return 0 end
end

function SendEmoteToHub(data, from)
	result, err = VH:SendDataToAll("<"..from.."> ".."/me "..data.."|",0,10)
	return 1
end

function VH_OnTimer()
	for nick,time in pairs(timeLeft) do
		if (time > 0) then
			timeLeft[nick] = timeLeft[nick] - 1
		end
	end
	
	for nick,count in pairs(chargin) do
		if (count >= 360) then
			--discharge on themselves
			chargin[nick] = 0
			damage = math.random(2,15)
			SendEmoteToHub("overloaded their cupcake charge!  It discharges on them for "..damage.." cupcakes!  :(", nick)
			while (damage > 0) do
				addCake(nick)
				damage = damage - 1
			end
		elseif (count == 300) then
			SendMessageToUser("Your cupcake is fully charged!", nick, bot_name)
			chargin[nick] = chargin[nick] + 1
		elseif (count > 0) then
			chargin[nick] = chargin[nick] + 1
		end
	end
	return 1
end

function VH_OnCloseConn(ip)
	if (forgive[ip] == true) then
		punish[ip] = false
		forgive[ip] = false
		timeLeft[ip] = 0
	elseif (timeLeft[ip] > 0) then
		punish[ip] = true
	end
	return 1
end

function VH_OnUserLogout(nick)
	chargin[nick] = 0
	return 1
end

function VH_OnUserLogin(nick)
	if (queue[nick] ~= nil) and (UserIsOnline(queue[nick])) then
		performCake(nick, queue[nick])
		queue[nick] = nil
	end
	return 1
end

function VH_OnNewConn(ip)
	forgive[ip] = false
	return 1
end
